﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using STPlatform.UPracticalMSSQLDatabaseV2;

namespace SimpleORM
{
    public abstract class ScriptFactory : CDObject, IScriptFactory
    {
        #region Properties

        public DParameterCollection Parameters { get; private set; }
        public StringBuilder CommandText { get; set; }
        public object ExecuteArgument { get; set; }
        public eCommandType? Type { get; set; }

        #endregion

        #region Fields

        private static Dictionary<eDataType, MethodInfo>
            dicDataTypes = DataTypeAttribute.GetMethods(typeof(IScriptFactory));

        #endregion

        #region Ctor

        public ScriptFactory()
        {
            Parameters = new DParameterCollection();
            CommandText = new StringBuilder();
        }

        #endregion

        #region Methods

        #region Methods - System

        public IScriptFactory New()
        {
            return Activator.CreateInstance(this.GetType()) as IScriptFactory;
        }

        public virtual IScriptFactory Combine(IScriptFactory exp)
        {
            return Concat(exp, "; ");
        }

        public virtual void Append(IScriptFactory exp)
        {
            if (exp == null)
                return;

            CommandText.Append("; ");
            CommandText.Append(exp.CommandText);
            Parameters.AddRange(exp.Parameters);
            if (ExecuteArgument == null)
                ExecuteArgument = exp.ExecuteArgument;
            if (Type == null)
                Type = exp.Type;
        }

        public virtual IScriptFactory Concat(IScriptFactory exp, string connector)
        {
            if (exp == null)
                return this;

            IScriptFactory f = Clone() as IScriptFactory;
            f.CommandText.Append(connector);
            f.CommandText.Append(exp.CommandText);
            f.Parameters.AddRange(exp.Parameters);
            if (f.ExecuteArgument == null)
                f.ExecuteArgument = exp.ExecuteArgument;
            if (f.Type == null)
                f.Type = exp.Type;

            return f;
        }

        public virtual IScriptFactory Concat(IScriptFactory exp)
        {
            return Concat(exp, " ");
        }

        public virtual IScriptFactory Constant(object value)
        {
            if (value == null)
                return this;

            IScriptFactory f = New();
            f.CommandText.Append(value.ToString());

            return f;
        }

        public virtual IScriptFactory Parameter(object value)
        {
            DParameter parameter = CreateParameter(value);

            IScriptFactory f = New();
            f.CommandText.Append(parameter.ValueString);
            f.Parameters.Add(parameter);

            return f;
        }

        public virtual IScriptFactory Stress()
        {
            return this;
        }

        public virtual IScriptFactory Bracket()
        {
            IScriptFactory f = Clone() as IScriptFactory;
            f.CommandText.Insert(0, '(');
            f.CommandText.Append(')');

            return f;
        }

        public virtual IScriptFactory As(IScriptFactory exp)
        {
            return this;
        }

        #endregion

        #region Methods - Script

        #region Methods - Script - Select

        public virtual IScriptFactory Select()
        {
            return this;
        }

        public virtual IScriptFactory Select(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Distinct(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Take(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Count()
        {
            return this;
        }

        public virtual IScriptFactory Count(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Average(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Sum(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Max(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Min(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Len(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Paging(IScriptFactory exp, IScriptFactory orderKey, eOrder order, int pageIndex, int pageSize)
        {
            return this;
        }

        #endregion

        #region Methods - Script - From

        public virtual IScriptFactory From(IScriptFactory exp)
        {
            return this;
        }

        #endregion

        #region Methods - Script - Where

        public virtual IScriptFactory Where(IScriptFactory exp)
        {
            return this;
        }

        #endregion

        #region Methods - Script - OrderBy

        public virtual IScriptFactory Ascending(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Descending(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory OrderBy(IScriptFactory exp)
        {
            return this;
        }

        #endregion

        #region Methods - Script - Join

        public virtual IScriptFactory Join(IScriptFactory target, IScriptFactory condition)
        {
            return this;
        }

        public virtual IScriptFactory JoinLeft(IScriptFactory target, IScriptFactory condition)
        {
            return this;
        }

        #endregion

        #region Methods - Script - GroupBy

        public virtual IScriptFactory GroupBy(IScriptFactory exp)
        {
            return this;
        }

        #endregion

        #region Methods - Script - Edit

        public virtual IScriptFactory Insert(IScriptFactory target, DParameter[] parameters)
        {
            return this;
        }

        public virtual IScriptFactory Update(IScriptFactory target, DParameter[] parameters)
        {
            return this;
        }

        public virtual IScriptFactory Update(IScriptFactory target, IScriptFactory values)
        {
            return this;
        }

        public virtual IScriptFactory Delete(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Replace(IScriptFactory source, IScriptFactory target)
        {
            return this;
        }

        public virtual IScriptFactory Substring(IScriptFactory source, IScriptFactory target)
        {
            return this;
        }

        public virtual IScriptFactory ConvertToString()
        {
            return this;
        }

        #endregion

        #endregion

        #region Methods - Expression

        public virtual IScriptFactory If(IScriptFactory condition, IScriptFactory ifTrue, IScriptFactory ifFalse)
        {
            return this;
        }

        public virtual IScriptFactory And(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Or(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Equal(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory NotEqual(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory GreaterThan(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory GreaterThanOrEqual(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory LessThan(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory LessThanOrEqual(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory StartWith(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory EndWith(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Contains(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Add(IScriptFactory exp)
        {
            if (exp == null)
                return this;

            IScriptFactory f = Clone() as IScriptFactory;
            f.CommandText.Insert(0, '(');
            f.CommandText.Append(')');
            f.CommandText.Append(" + ");
            f.CommandText.Append('(');
            f.CommandText.Append(exp.CommandText);
            f.CommandText.Append(')');
            f.Parameters.AddRange(exp.Parameters);

            return f;
        }

        public virtual IScriptFactory Subtract(IScriptFactory exp)
        {
            if (exp == null)
                return this;

            IScriptFactory f = Clone() as IScriptFactory;
            f.CommandText.Insert(0, '(');
            f.CommandText.Append(')');
            f.CommandText.Append(" - ");
            f.CommandText.Append('(');
            f.CommandText.Append(exp.CommandText);
            f.CommandText.Append(')');
            f.Parameters.AddRange(exp.Parameters);

            return f;
        }

        public virtual IScriptFactory Divide(IScriptFactory exp)
        {
            if (exp == null)
                return this;

            IScriptFactory f = Clone() as IScriptFactory;
            f.CommandText.Insert(0, '(');
            f.CommandText.Append(')');
            f.CommandText.Append(" / ");
            f.CommandText.Append('(');
            f.CommandText.Append(exp.CommandText);
            f.CommandText.Append(')');
            f.Parameters.AddRange(exp.Parameters);

            return f;
        }

        public virtual IScriptFactory Multiply(IScriptFactory exp)
        {
            if (exp == null)
                return this;

            IScriptFactory f = Clone() as IScriptFactory;
            f.CommandText.Insert(0, '(');
            f.CommandText.Append(')');
            f.CommandText.Append(" * ");
            f.CommandText.Append('(');
            f.CommandText.Append(exp.CommandText);
            f.CommandText.Append(')');
            f.Parameters.AddRange(exp.Parameters);

            return f;
        }

        public virtual IScriptFactory Intersect(IScriptFactory exp)
        {
            return this;
        }

        public virtual IScriptFactory Within(IScriptFactory exp)
        {
            return this;
        }


        #endregion

        #region Methods - Parameter

        public virtual DParameter CreateParameter()
        {
            return null;
        }

        public virtual DParameter CreateParameter(string paramName, object paramValue)
        {
            DParameter parameter = CreateParameter();
            parameter.Name = paramName;
            parameter.Value = paramValue;

            return parameter;
        }

        public DParameter CreateParameter(object paramValue)
        {
            return CreateParameter(string.Empty, paramValue);
        }

        public virtual DParameter CreateParameter(string paramName, object paramValue, object paramType)
        {
            DParameter parameter = CreateParameter(paramName, paramValue);
            parameter.Type = paramType;

            return parameter;
        }

        #endregion

        #region Methods - Compile

        public virtual void Compile()
        {
            foreach (DParameter parameter in Parameters)
                CommandText = CommandText.Replace(parameter.ParameterName, parameter.ValueString);
        }

        #endregion

        #region Methods - System

        public override string ToString()
        {
            return CommandText.ToString();
        }

        public override object Clone()
        {
            ScriptFactory f = base.Clone() as ScriptFactory;
            f.Parameters = Parameters.Clone() as DParameterCollection;
            f.CommandText = new StringBuilder(CommandText.ToString());

            return f;
        }

        #endregion

        #region Methods - Type

        public virtual eDataType GetDataType(string type)
        {
            throw new NotImplementedException();
        }

        public virtual string GetDataType(eDataType type, params object[] parameters)
        {
            return (string)dicDataTypes[type].Invoke(this, new object[] { parameters });
        }

        public virtual string GetBooleanType(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetFloatType(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetDoubleType(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetDecimalType(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetByteType(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetInt16Type(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetInt32Type(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetInt64Type(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetStringType(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetGuidType(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetDateTimeType(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetBinaryType(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetObjectType(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public virtual string GetGeometryType(params object[] parameters)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Methods - Object

        public virtual IScriptFactory CreateObject(string schema, string objName, DataColumnAttribute[] cols)
        {
            return this;
        }

        public virtual IScriptFactory DropObject(string schema, string objName)
        {
            return this;
        }

        public virtual IScriptFactory SchemaObject(string schema, string objName)
        {
            return this;
        }

        public virtual IScriptFactory RenameObject(string schema, string objName, string objNameNew)
        {
            return this;
        }

        public virtual IScriptFactory CreateProperty(string schema, string objName, DataColumnAttribute col)
        {
            return this;
        }

        public virtual IScriptFactory DropProperty(string schema, string objName, string colName)
        {
            return this;
        }

        public virtual IScriptFactory AlterProperty(string schema, string objName, DataColumnAttribute col)
        {
            return this;
        }

        public virtual IScriptFactory FormatProperty(DataColumnAttribute col)
        {
            return this;
        }

        #endregion

        #endregion
    }
}
